#!/usr/bin/env python3
"""
BoLe智能HR系统 - 基于多智能体框架的真实智能回复系统
集成LangGraph多智能体架构，提供真正的AI驱动的招聘管理
"""

import os
import sys
import asyncio
import logging
import time
import re
from pathlib import Path
from typing import Dict, Any, Optional, List, Set
from datetime import datetime
from dotenv import load_dotenv

# 添加项目路径
current_dir = Path(__file__).parent
sys.path.append(str(current_dir))

# 加载环境变量 - 从项目根目录加载
project_root = current_dir.parent.parent
env_path = project_root / '.env'
load_dotenv(env_path)

# FastAPI imports
from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect, Request
from fastapi.staticfiles import StaticFiles
from fastapi.responses import HTMLResponse, JSONResponse, FileResponse
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
import json

# 本地模块
from data_manager import data_manager
from multi_agent_system import multi_agent_hr_system, MultiAgentHRSystem, add_status_callback, remove_status_callback

# 日志配置
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler(sys.stdout),
        logging.FileHandler(f"logs/hr_system_{datetime.now().strftime('%Y%m%d')}.log", mode='a', encoding='utf-8')
    ]
)
logger = logging.getLogger(__name__)

# 创建logs目录
os.makedirs("logs", exist_ok=True)

# FastAPI 应用
app = FastAPI(
    title="BoLe 智能HR系统 - 多智能体版",
    description="基于LangGraph多智能体架构的真实AI招聘管理系统",
    version="3.0.0-MultiAgent"
)

# CORS 配置
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True, 
    allow_methods=["*"],
    allow_headers=["*"],
)

# 静态文件服务配置
frontend_dir = os.path.join(os.path.dirname(__file__), "frontend")
if os.path.exists(frontend_dir):
    # 主静态文件路由
    app.mount("/static", StaticFiles(directory=frontend_dir), name="static")
    
    # 样式文件路由
    styles_dir = os.path.join(frontend_dir, "styles")
    if os.path.exists(styles_dir):
        app.mount("/styles", StaticFiles(directory=styles_dir), name="styles")
        logger.info(f"✅ 样式文件已挂载: {styles_dir}")
    
    # 脚本文件路由
    scripts_dir = os.path.join(frontend_dir, "scripts")
    if os.path.exists(scripts_dir):
        app.mount("/scripts", StaticFiles(directory=scripts_dir), name="scripts")
        logger.info(f"✅ 脚本文件已挂载: {scripts_dir}")
        
    logger.info(f"✅ 前端静态文件已挂载: {frontend_dir}")

# WebSocket连接管理器
class WebSocketManager:
    """WebSocket连接管理器"""
    
    def __init__(self):
        self.active_connections: Set[WebSocket] = set()
    
    async def connect(self, websocket: WebSocket):
        """接受WebSocket连接"""
        await websocket.accept()
        self.active_connections.add(websocket)
        logger.info(f"✅ WebSocket连接建立，当前连接数: {len(self.active_connections)}")
    
    def disconnect(self, websocket: WebSocket):
        """断开WebSocket连接"""
        self.active_connections.discard(websocket)
        logger.info(f"❌ WebSocket连接断开，当前连接数: {len(self.active_connections)}")
    
    async def send_status_update(self, status_data: Dict[str, Any]):
        """向所有连接的客户端发送状态更新"""
        if not self.active_connections:
            return
        
        message = json.dumps({
            "type": "status_update",
            "data": status_data
        }, ensure_ascii=False)
        
        # 创建副本以避免在迭代时修改集合
        connections_copy = self.active_connections.copy()
        
        for connection in connections_copy:
            try:
                await connection.send_text(message)
            except Exception as e:
                logger.error(f"发送WebSocket消息失败: {e}")
                # 移除失效连接
                self.active_connections.discard(connection)

# 全局WebSocket管理器
websocket_manager = WebSocketManager()

# 全局状态
app_state = {
    "initialized": False,
    "start_time": datetime.now(),
    "request_count": 0,
    "error_count": 0,
    "candidate_status": {},  # 存储候选人状态
    "candidate_notes": {}    # 存储候选人笔记
}

class CandidateStatus:
    """候选人状态枚举"""
    CONFIRMED = "confirmed"    # 确认 - 绿色
    PENDING = "pending"        # 待定 - 黄色  
    REJECTED = "rejected"      # 拒绝 - 红色
    UNKNOWN = "unknown"        # 未知 - 灰色

class HRSystem:
    """BoLe智能HR系统 - 多智能体版本"""
    
    def __init__(self):
        self.initialized = False
        self.multi_agent_system = None
        self.request_timeout = 180  # 增加到180秒超时，适应复杂多智能体处理
    
    def initialize(self):
        """初始化系统"""
        logger.info("🚀 初始化BoLe智能HR多智能体系统...")
        
        try:
            # 初始化多智能体系统
            success = multi_agent_hr_system.initialize()
            if success:
                self.multi_agent_system = multi_agent_hr_system
                self.initialized = True
                logger.info(f"✅ 多智能体HR系统初始化成功: {len(data_manager.resumes)}个简历, {len(data_manager.jobs)}个岗位")
                logger.info("🎯 智能体架构: Interaction → Orchestrator → Specialists → Tools → Completion")
            else:
                logger.error("❌ 多智能体系统初始化失败")
                
        except Exception as e:
            logger.error(f"❌ 多智能体系统初始化异常: {e}")
            import traceback
            logger.error(traceback.format_exc())
            
        return self.initialized
    
    async def _status_callback(self, status_data: Dict[str, Any]):
        """状态更新回调函数，用于推送实时状态到WebSocket客户端"""
        await websocket_manager.send_status_update(status_data)
    
    async def process_request(self, user_message: str, user_id: str = "user") -> Dict[str, Any]:
        """处理用户请求 - 使用多智能体系统"""
        request_id = f"req_{int(time.time() * 1000)}"
        
        try:
            logger.info(f"[{request_id}] 🎯 开始处理多智能体请求: {user_message[:100]}...")
            
            if not self.initialized or not self.multi_agent_system:
                return {"success": False, "error": "多智能体系统未初始化"}
            
            # 注册状态回调
            add_status_callback(self._status_callback)
            
            # 直接调用多智能体系统处理请求
            logger.info(f"[{request_id}] 🤖 调用多智能体系统处理请求...")
            
            # 设置超时处理
            start_time = time.time()
            
            try:
                # 调用多智能体系统
                result = await asyncio.wait_for(
                    self.multi_agent_system.process_request(user_message, user_id),
                    timeout=self.request_timeout
                )
                
                processing_time = time.time() - start_time
                logger.info(f"[{request_id}] ✅ 多智能体系统处理完成，耗时: {processing_time:.2f}秒")
                
                # 转换为前端兼容的格式
                formatted_result = await self.format_agent_response(result, request_id)
                
                return formatted_result
                
            except asyncio.TimeoutError:
                logger.error(f"[{request_id}] ⏰ 多智能体系统处理超时 ({self.request_timeout}秒)")
            return {
                "success": False,
                    "error": "处理超时",
                    "message": "系统处理时间过长，请稍后重试",
                "request_id": request_id
            }
        
        except Exception as e:
            logger.error(f"[{request_id}] ❌ 多智能体系统处理失败: {e}")
            import traceback
            logger.error(traceback.format_exc())
        
            return {
                "success": False,
                "error": str(e),
                "message": f"多智能体系统处理失败：{str(e)}",
                "request_id": request_id
            }
        finally:
            # 无论如何都要注销回调
            remove_status_callback(self._status_callback)
        
    async def format_agent_response(self, agent_result: Dict[str, Any], request_id: str) -> Dict[str, Any]:
        """将多智能体系统的响应格式化为前端兼容格式"""
        try:
            logger.info(f"[{request_id}] 📋 格式化多智能体响应...")
            
            # 基础响应结构
            formatted_response = {
                "success": agent_result.get("success", True),
                "message": agent_result.get("message", "处理完成"),
                "status": agent_result.get("status", "completed"),
                "agent_workflow": agent_result.get("agent_workflow", "Multi-Agent System"),
                "request_id": request_id,
                "timestamp": datetime.now().isoformat(),
                "server_info": {
                    "version": "Multi-Agent Version 3.0",
                    "system_type": "LangGraph Multi-Agent HR System"
                }
            }
            
            # 处理候选人数据
            candidates_data = []
            
            # 从多智能体结果中直接获取候选人数据
            if "candidates" in agent_result:
                candidates_data = agent_result["candidates"]
            
            # 从analysis_results中提取候选人数据
            analysis_results = agent_result.get("analysis_results", {})
            if "candidates" in analysis_results:
                candidates_data.extend(analysis_results["candidates"])
            
            # 从task_results中提取候选人数据
            task_results = agent_result.get("task_results", {})
            for key, value in task_results.items():
                if isinstance(value, list) and value:
                    # 检查是否是候选人数据
                    if isinstance(value[0], dict) and "id" in value[0]:
                        candidates_data.extend(value)
            
            # 格式化候选人数据
            if candidates_data:
                formatted_candidates = []
                for candidate in candidates_data:
                    # 确保候选人数据包含必要字段
                    formatted_candidate = {
                        'candidate_id': candidate.get('id', candidate.get('candidate_id', 'unknown')),
                        'id': candidate.get('id', candidate.get('candidate_id', 'unknown')),
                        'name': candidate.get('name', f"候选人_{candidate.get('id', 'unknown')[:8]}"),
                        'skills': candidate.get('skills', []),
                        'experience_years': candidate.get('experience', candidate.get('experience_years', 0)),
                        'location': candidate.get('location', '位置未知'),
                        'category': candidate.get('category', '未分类'),
                        'status': app_state["candidate_status"].get(candidate.get('id', ''), CandidateStatus.UNKNOWN),
                        'status_color': self.get_status_color(app_state["candidate_status"].get(candidate.get('id', ''), CandidateStatus.UNKNOWN)),
                        'score': candidate.get('score', candidate.get('overall_score', 8.0)),
                        'match_score': candidate.get('match_score', candidate.get('total_score', 85)),
                        'content': candidate.get('resume_preview', candidate.get('content', ''))[:200] + "..." if len(candidate.get('content', '')) > 200 else candidate.get('content', ''),
                        'resume_full_text': candidate.get('resume_full_text', candidate.get('content', '')),
                        'analysis_reasoning': candidate.get('reasoning', candidate.get('analysis_reasoning', '通过多智能体系统分析'))
                    }
                    formatted_candidates.append(formatted_candidate)
                
                formatted_response["analyzed_candidates"] = formatted_candidates
            
            # 处理面试题生成
            if "interview_questions" in analysis_results:
                formatted_response["interview_questions"] = analysis_results["interview_questions"]
            
            # 处理UI指令
            ui_commands = []
            if formatted_response.get("analyzed_candidates"):
                ui_commands.append({
                    "command": "UPDATE_CANDIDATE_LIST", 
                    "payload": formatted_response["analyzed_candidates"]
                })
            
            if formatted_response.get("interview_questions"):
                ui_commands.append({
                    "command": "SHOW_INTERVIEW_QUESTIONS",
                    "payload": formatted_response["interview_questions"]
                })
            
            # 从多智能体结果中获取UI指令
            agent_ui_commands = agent_result.get("ui_commands", [])
            ui_commands.extend(agent_ui_commands)
            
            formatted_response["ui_commands"] = ui_commands
            
            # 处理深度分析结果
            if "report" in analysis_results:
                # 深度分析报告
                report = analysis_results["report"]
                if "visualizations" in report:
                    ui_commands.append({
                        "command": "SHOW_VISUALIZATIONS",
                        "payload": report["visualizations"]
                    })
                
                formatted_response["deep_analysis"] = report
            
            logger.info(f"[{request_id}] ✅ 多智能体响应格式化完成")
            return formatted_response
            
        except Exception as e:
            logger.error(f"[{request_id}] ❌ 格式化响应失败: {e}")
            return {
                "success": False,
                "error": f"格式化响应失败: {str(e)}",
                "message": "系统内部错误，请重试",
                "request_id": request_id
            }
        
    async def update_candidate_status_direct(self, candidate_id: str, new_status: str) -> Dict[str, Any]:
        """直接更新候选人状态 - 保留为API使用"""
        try:
            # 验证状态值
            valid_statuses = [CandidateStatus.CONFIRMED, CandidateStatus.PENDING, CandidateStatus.REJECTED, CandidateStatus.UNKNOWN]
            if new_status not in valid_statuses:
                return {"success": False, "error": "无效的状态值"}
            
            # 验证候选人存在
            resume = data_manager.get_resume_by_id(candidate_id)
            if not resume:
                return {"success": False, "error": "候选人不存在"}
        
            # 更新状态
            app_state["candidate_status"][candidate_id] = new_status
            
            return {
                "success": True,
                    "message": f"候选人 {candidate_id} 状态已更新",
                "candidate_id": candidate_id,
                "new_status": new_status,
                    "status_color": self.get_status_color(new_status)
                }
            
        except Exception as e:
            logger.error(f"更新候选人状态失败: {e}")
            return {"success": False, "error": str(e)}
    


    
    def get_status_color(self, status: str) -> str:
        """获取状态对应的颜色"""
        color_map = {
            CandidateStatus.CONFIRMED: "#22c55e",  # 绿色
            CandidateStatus.PENDING: "#eab308",    # 黄色
            CandidateStatus.REJECTED: "#ef4444",   # 红色
            CandidateStatus.UNKNOWN: "#6b7280"     # 灰色
        }
        return color_map.get(status, "#6b7280")

# 创建HR系统实例
hr_system = HRSystem()

@app.on_event("startup")
async def startup_event():
    """应用启动事件"""
    logger.info("🚀 启动BoLe智能HR多智能体系统...")
    
    success = hr_system.initialize()
    if success:
        app_state["initialized"] = True
        logger.info("✅ BoLe智能HR多智能体系统启动成功!")
        logger.info("🤖 系统架构: LangGraph多智能体 → 真实AI驱动")
    else:
        logger.error("❌ BoLe智能HR多智能体系统启动失败")
        app_state["initialized"] = False

@app.get("/", response_class=HTMLResponse)
async def serve_index():
    """服务首页"""
    frontend_path = os.path.join(frontend_dir, "job_selection.html")
    if os.path.exists(frontend_path):
        return FileResponse(frontend_path)
    else:
        return HTMLResponse("""
        <!DOCTYPE html>
        <html>
        <head>
            <title>BoLe 智能HR系统 - 多智能体版</title>
            <meta charset="utf-8">
            <style>
                body { font-family: Arial, sans-serif; margin: 40px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; }
                .container { max-width: 900px; margin: 0 auto; background: white; padding: 40px; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); }
                .header { text-align: center; margin-bottom: 40px; }
                .header h1 { color: #2c3e50; margin-bottom: 10px; }
                .header .subtitle { color: #7f8c8d; font-size: 18px; margin-bottom: 20px; }
                .badge { display: inline-block; padding: 5px 15px; background: linear-gradient(45deg, #3498db, #2ecc71); color: white; border-radius: 20px; font-weight: bold; margin-bottom: 20px; }
                .feature { margin: 20px 0; padding: 20px; background: linear-gradient(135deg, #f8f9fa, #e9ecef); border-radius: 10px; border-left: 5px solid #007bff; }
                .feature h3 { color: #2c3e50; margin-bottom: 15px; }
                .agent-flow { background: linear-gradient(90deg, #667eea, #764ba2); color: white; padding: 20px; border-radius: 10px; margin: 20px 0; text-align: center; }
                .status-demo { display: flex; gap: 10px; margin: 15px 0; flex-wrap: wrap; }
                .status-badge { padding: 8px 15px; border-radius: 20px; color: white; font-weight: bold; }
                .confirmed { background: linear-gradient(45deg, #27ae60, #2ecc71); }
                .pending { background: linear-gradient(45deg, #f39c12, #e67e22); }
                .rejected { background: linear-gradient(45deg, #e74c3c, #c0392b); }
                .unknown { background: linear-gradient(45deg, #95a5a6, #7f8c8d); }
                .tech-stack { background: #2c3e50; color: white; padding: 20px; border-radius: 10px; margin: 20px 0; }
                .tech-item { display: inline-block; margin: 5px; padding: 5px 10px; background: #3498db; border-radius: 15px; font-size: 12px; }
            </style>
        </head>
        <body>
            <div class="container">
                <div class="header">
                    <h1>🤖 BoLe 智能HR系统</h1>
                    <div class="subtitle">基于LangGraph多智能体架构的真实AI招聘管理系统</div>
                    <div class="badge">Multi-Agent Version 3.0</div>
                </div>
                
                <div class="agent-flow">
                    <h3>🧠 多智能体工作流</h3>
                    <p>Interaction → Orchestrator → CandidateAnalysis → DeepAnalysis → Tools → Completion</p>
                </div>
                
                <div class="feature">
                    <h3>🔍 智能候选人分析</h3>
                    <p>• <strong>语义理解</strong>：'找几个身心健康、积极主动的Python工程师'<br>
                    • <strong>深度分析</strong>：'为候选人12345678生成深度分析报告'<br>
                    • <strong>技能匹配</strong>：'筛选5年以上经验的机器学习专家'<br>
                    • <strong>可视化分析</strong>：自动生成能力雷达图和技能对比图</p>
                </div>
                
                <div class="feature">
                    <h3>🎯 多智能体协作</h3>
                    <p><strong>Orchestrator（总调度）</strong>：分析用户意图，智能路由任务<br>
                    <strong>CandidateAnalysis（分析师）</strong>：执行候选人搜索和匹配度分析<br>
                    <strong>DeepAnalysis（深度分析师）</strong>：生成雷达图、对比图、综合报告<br>
                    <strong>RecordKeeping（记录员）</strong>：管理候选人状态和数据更新<br>
                    <strong>WorkbenchUI（界面管家）</strong>：生成前端展示指令</p>
                </div>
                
                <div class="feature">
                    <h3>📊 智能状态管理</h3>
                    <p>AI驱动的候选人状态跟踪：</p>
                    <div class="status-demo">
                        <span class="status-badge confirmed">🟢 确认通过</span>
                        <span class="status-badge pending">🟡 待定评估</span>
                        <span class="status-badge rejected">🔴 不符合要求</span>
                        <span class="status-badge unknown">⚪ 待分析</span>
                    </div>
                </div>
                
                <div class="tech-stack">
                    <h3>🛠️ 技术架构</h3>
                    <div>
                        <span class="tech-item">LangGraph</span>
                        <span class="tech-item">LangChain</span>
                        <span class="tech-item">OpenAI/通义千问</span>
                        <span class="tech-item">FastAPI</span>
                        <span class="tech-item">异步处理</span>
                        <span class="tech-item">Tool Calling</span>
                        <span class="tech-item">RAG检索</span>
                        <span class="tech-item">语义分析</span>
                    </div>
                </div>
                
                <div class="feature">
                    <h3>🌐 API接口</h3>
                    <p>• <strong>POST /api/chat</strong> - 多智能体对话接口<br>
                    • <strong>GET /api/status</strong> - 系统状态监控<br>
                    • <strong>GET /living_workspace.html</strong> - Living Workspace界面<br>
                    • <strong>GET /api/candidates/status</strong> - 候选人状态统计</p>
                </div>
            </div>
        </body>
        </html>
        """, status_code=200)

@app.get("/api/status")
async def get_status():
    """获取系统状态"""
    try:
        uptime = (datetime.now() - app_state["start_time"]).total_seconds()
        
        # 统计候选人状态
        status_stats = {
            "confirmed": 0,
            "pending": 0, 
            "rejected": 0,
            "unknown": 0
        }
        
        for status in app_state["candidate_status"].values():
            if status in status_stats:
                status_stats[status] += 1
        
        total_candidates = len(data_manager.resumes) if app_state["initialized"] else 0
        status_stats["unknown"] = total_candidates - sum(status_stats.values()) + status_stats["unknown"]
        
        return JSONResponse(content={
            "success": True,
            "system_status": "healthy" if app_state["initialized"] else "error",
            "initialized": app_state["initialized"],
            "uptime_seconds": uptime,
            "candidate_count": total_candidates,
            "job_count": len(data_manager.jobs) if app_state["initialized"] else 0,
            "request_count": app_state["request_count"],
            "error_count": app_state["error_count"],
            "candidate_status_stats": status_stats,
            "timestamp": datetime.now().isoformat(),
            "version": "3.0.0-MultiAgent",
            "system_type": "LangGraph Multi-Agent HR System"
        })
        
    except Exception as e:
        logger.error(f"获取状态失败: {e}")
        return JSONResponse(content={
            "success": False,
            "error": str(e)
        }, status_code=500)

@app.post("/api/chat")
async def chat_endpoint(request_data: Dict[str, Any]):
    """聊天接口"""
    try:
        if not app_state["initialized"]:
            raise HTTPException(status_code=503, detail="系统尚未初始化完成，请稍后重试")
        
        message = request_data.get("message", "").strip()
        user_id = request_data.get("user_id", "user")
        
        if not message:
            raise HTTPException(status_code=400, detail="消息不能为空")
        
        # 增加请求计数
        app_state["request_count"] += 1
        
        logger.info(f"💬 收到用户消息: {message[:50]}...")
        
        # 处理消息
        response_data = await hr_system.process_request(message, user_id)
        
        # 添加UI指令
        ui_commands = []
        if response_data.get("analyzed_candidates"):
            ui_commands.append({
                "command": "UPDATE_CANDIDATE_LIST",
                "payload": response_data["analyzed_candidates"]
            })
        
        if response_data.get("interview_questions"):
            ui_commands.append({
                "command": "SHOW_INTERVIEW_QUESTIONS",
                "payload": response_data["interview_questions"]
            })
        
        if response_data.get("new_status"):
            ui_commands.append({
                "command": "UPDATE_CANDIDATE_STATUS",
                "payload": {
                    "candidate_id": response_data.get("candidate_id"),
                    "status": response_data.get("new_status"),
                    "color": response_data.get("status_color")
                }
            })
        
        # 返回响应
        enhanced_response = {
            **response_data,
            "ui_commands": ui_commands,
            "candidate_count": len(data_manager.resumes),
            "timestamp": datetime.now().isoformat(),
            "server_info": {
                "version": "Fixed Version 2.1",
                "request_id": app_state["request_count"]
            }
        }
        
        return JSONResponse(content=enhanced_response)
        
    except HTTPException as e:
        raise e
    except Exception as e:
        app_state["error_count"] += 1
        logger.error(f"💥 聊天处理失败: {e}")
        import traceback
        logger.error(traceback.format_exc())
        
        return JSONResponse(content={
            "success": False,
            "error": f"处理消息时发生错误: {str(e)}",
            "action_type": "error",
            "timestamp": datetime.now().isoformat()
        }, status_code=500)

@app.get("/api/candidates/status")
async def get_candidates_status():
    """获取候选人状态统计"""
    try:
        if not app_state["initialized"]:
            raise HTTPException(status_code=503, detail="系统尚未初始化完成")
        
        # 统计状态
        status_stats = {
            "confirmed": {"count": 0, "color": "#22c55e", "label": "确认"},
            "pending": {"count": 0, "color": "#eab308", "label": "待定"},
            "rejected": {"count": 0, "color": "#ef4444", "label": "拒绝"},
            "unknown": {"count": 0, "color": "#6b7280", "label": "未知"}
        }
        
        for status in app_state["candidate_status"].values():
            if status in status_stats:
                status_stats[status]["count"] += 1
        
        total_candidates = len(data_manager.resumes)
        status_stats["unknown"]["count"] = total_candidates - sum(s["count"] for s in status_stats.values()) + status_stats["unknown"]["count"]
        
        return JSONResponse(content={
            "success": True,
            "total_candidates": total_candidates,
            "status_statistics": status_stats,
            "timestamp": datetime.now().isoformat()
        })
        
    except Exception as e:
        logger.error(f"获取候选人状态统计失败: {e}")
        return JSONResponse(content={
            "success": False,
            "error": str(e)
        }, status_code=500)

@app.post("/api/candidates/{candidate_id}/status")
async def update_candidate_status_api(candidate_id: str, request_data: Dict[str, Any]):
    """更新候选人状态API"""
    try:
        if not app_state["initialized"]:
            raise HTTPException(status_code=503, detail="系统尚未初始化完成")
        
        new_status = request_data.get("status", CandidateStatus.UNKNOWN)
        
        # 验证状态值
        valid_statuses = [CandidateStatus.CONFIRMED, CandidateStatus.PENDING, CandidateStatus.REJECTED, CandidateStatus.UNKNOWN]
        if new_status not in valid_statuses:
            raise HTTPException(status_code=400, detail="无效的状态值")
        
        # 验证候选人存在
        resume = data_manager.get_resume_by_id(candidate_id)
        if not resume:
            raise HTTPException(status_code=404, detail="候选人不存在")
        
        # 使用HR系统的direct方法更新状态
        result = await hr_system.update_candidate_status_direct(candidate_id, new_status)
        
        if result["success"]:
            return JSONResponse(content={
                **result,
                "timestamp": datetime.now().isoformat(),
                "system_type": "Multi-Agent Status Update"
            })
        else:
            return JSONResponse(content=result, status_code=400)
        
    except HTTPException as e:
        raise e
    except Exception as e:
        logger.error(f"更新候选人状态失败: {e}")
        return JSONResponse(content={
            "success": False,
            "error": str(e)
        }, status_code=500)

# ==================== WebSocket 路由 ====================

@app.websocket("/ws/status")
async def websocket_endpoint(websocket: WebSocket):
    """WebSocket端点，用于实时状态推送"""
    await websocket_manager.connect(websocket)
    
    try:
        # 发送连接成功消息
        await websocket.send_text(json.dumps({
            "type": "connection_established",
            "data": {
                "message": "实时状态连接已建立",
                "timestamp": datetime.now().isoformat()
            }
        }, ensure_ascii=False))
        
        # 保持连接活跃，等待消息
        while True:
            # 接收客户端消息（如心跳包）
            try:
                data = await asyncio.wait_for(websocket.receive_text(), timeout=30.0)
                message = json.loads(data)
                
                # 处理心跳包
                if message.get("type") == "ping":
                    await websocket.send_text(json.dumps({
                        "type": "pong",
                        "data": {"timestamp": datetime.now().isoformat()}
                    }, ensure_ascii=False))
                    
            except asyncio.TimeoutError:
                # 发送心跳包给客户端
                await websocket.send_text(json.dumps({
                    "type": "heartbeat",
                    "data": {"timestamp": datetime.now().isoformat()}
                }, ensure_ascii=False))
                
    except WebSocketDisconnect:
        websocket_manager.disconnect(websocket)
        logger.info("WebSocket客户端主动断开连接")
    except Exception as e:
        logger.error(f"WebSocket连接异常: {e}")
        websocket_manager.disconnect(websocket)

# ==================== 补充缺失的API路由 ====================

@app.get("/api/hr/overview")
async def hr_overview_endpoint():
    """HR系统概览数据接口"""
    try:
        if not app_state["initialized"]:
            raise HTTPException(status_code=503, detail="系统尚未初始化完成，请稍后重试")
        
        app_state["request_count"] += 1
        
        # 获取基础统计数据
        total_candidates = len(data_manager.resumes)
        
        return JSONResponse(content={
            "success": True,
            "data": {
                "totalCandidates": total_candidates,
                "matchedCandidates": min(total_candidates, 23),  # 模拟匹配数据
                "avgMatchScore": 75.8,
                "topSkill": "Python",
                "systemStatus": "运行正常",
                "lastUpdate": datetime.now().isoformat()
            },
            "timestamp": datetime.now().isoformat()
        })
        
    except Exception as e:
        app_state["error_count"] += 1
        logger.error(f"❌ 概览数据接口错误: {str(e)}")
        return JSONResponse(content={
            "success": False,
            "error": f"概览数据服务错误: {str(e)}",
            "timestamp": datetime.now().isoformat()
        }, status_code=500)

@app.get("/api/hr/jobs")
async def get_jobs_endpoint():
    """获取岗位列表API"""
    try:
        if not app_state["initialized"]:
            raise HTTPException(status_code=503, detail="系统尚未初始化完成，请稍后重试")
        
        # 获取岗位数据
        jobs_data = []
        for job in data_manager.jobs:
            job_info = {
                "id": job.id,
                "title": job.title,
                "short_title": job.short_title,
                "company_name": job.company_name,
                "location": job.location,
                "schedule_type": job.schedule_type,
                "work_from_home": job.work_from_home,
                "salary_year_avg": job.salary_year_avg,
                "required_skills": job.required_skills or [],
                "preferred_skills": job.preferred_skills or [],
                "min_experience_years": job.min_experience_years,
                "description": job.description
            }
            jobs_data.append(job_info)
        
        return JSONResponse(content={
            "success": True,
            "jobs": jobs_data,
            "total_count": len(jobs_data),
            "message": f"成功获取 {len(jobs_data)} 个岗位信息",
            "timestamp": datetime.now().isoformat()
        })
        
    except Exception as e:
        logger.error(f"获取岗位列表失败: {str(e)}")
        return JSONResponse(content={
            "success": False,
            "error": str(e),
            "message": "获取岗位列表失败"
        }, status_code=500)

@app.get("/living_workspace.html", response_class=HTMLResponse)
async def serve_living_workspace():
    """直接访问Living Workspace界面"""
    workspace_path = os.path.join(frontend_dir, "living_workspace.html")
    if os.path.exists(workspace_path):
        return FileResponse(workspace_path)
    else:
        return HTMLResponse("<h1>Living Workspace未找到</h1>", status_code=404)

@app.get("/api/candidates")
async def get_candidates(limit: int = 20, offset: int = 0):
    """获取候选人列表"""
    try:
        if not app_state["initialized"]:
            raise HTTPException(status_code=503, detail="系统尚未初始化完成")
        
        candidates = data_manager.resumes[offset:offset + limit]
        
        candidate_list = []
        for resume in candidates:
            candidate_status = app_state["candidate_status"].get(resume.id, CandidateStatus.UNKNOWN)
            candidate_list.append({
                "id": resume.id,
                "name": f"候选人_{resume.id}",
                "category": resume.category,
                "skills": resume.skills,
                "experience_years": resume.experience_years,
                "status": candidate_status,
                "status_color": hr_system.get_status_color(candidate_status),
                "tags": [],
                "notes_count": 0
            })
        
        return JSONResponse(content={
            "success": True,
            "data": candidate_list,
            "total": len(data_manager.resumes),
            "offset": offset,
            "limit": limit
        })
        
    except Exception as e:
        logger.error(f"获取候选人失败: {e}")
        return JSONResponse(content={
            "success": False,
            "error": str(e)
        }, status_code=500)

@app.get("/api/candidates/{candidate_id}")
async def get_candidate_details(candidate_id: str):
    """获取单个候选人详细信息"""
    try:
        if not app_state["initialized"]:
            raise HTTPException(status_code=503, detail="系统尚未初始化完成")
        
        logger.info(f"🔍 获取候选人详情: {candidate_id}")
        
        # 从数据管理器获取候选人信息
        resume = data_manager.get_resume_by_id(candidate_id)
        if not resume:
            return JSONResponse(content={
                "success": False,
                "error": f"未找到候选人 {candidate_id}"
            }, status_code=404)
        
        # 获取候选人状态
        candidate_status = app_state["candidate_status"].get(candidate_id, CandidateStatus.UNKNOWN)
        
        # 构建详细的候选人信息
        candidate_details = {
            "id": resume.id,
            "name": f"候选人_{resume.id}",
            "category": resume.category,
            "Category": resume.category,  # 兼容性字段
            "skills": resume.skills,
            "experience": resume.experience_years,
            "experience_years": resume.experience_years,
            "location": resume.location,
            "status": candidate_status,
            "status_color": hr_system.get_status_color(candidate_status),
            
            # 简历内容 - 提供多种格式
            "content": resume.content,              # 文本格式
            "Resume_str": resume.content,           # 兼容性字段
            "html_content": resume.html_content,    # HTML格式
            "Resume_html": resume.html_content,     # 兼容性字段
            "resume_full_text": resume.content,     # 完整文本
            
            # 分析相关数据
            "score": 8.0 + (hash(candidate_id) % 20) / 10,  # 基于ID生成一致的分数
            "match_score": 85 + (hash(candidate_id) % 30),   # 基于ID生成一致的匹配分数
            
            # 时间戳
            "created_at": "2024-01-01",
            "updated_at": "2024-01-01",
            
            # 额外信息
            "tags": [],
            "notes": "",
            "interview_notes": "",
            "相关性": "高度相关" if resume.category == "HR" else "相关"
        }
        
        logger.info(f"✅ 候选人详情获取成功: {candidate_id}")
        
        return JSONResponse(content={
            "success": True,
            "candidate": candidate_details
        })
        
    except Exception as e:
        logger.error(f"❌ 获取候选人详情失败: {e}")
        return JSONResponse(content={
            "success": False,
            "error": str(e)
        }, status_code=500)

@app.post("/api/candidates/{candidate_id}/notes")
async def save_candidate_notes(candidate_id: str, request: Request):
    """保存候选人笔记"""
    try:
        body = await request.json()
        notes = body.get("notes", "")
        
        logger.info(f"📝 保存候选人 {candidate_id} 的笔记")
        
        # 存储笔记到全局状态
        app_state["candidate_notes"][candidate_id] = {
            "notes": notes,
            "updated_at": datetime.now().isoformat(),
            "updated_by": "HR"
        }
        
        # 同时更新简历对象的笔记字段
        for resume in data_manager.resumes:
            if resume.id == candidate_id:
                resume.notes = notes
                break
        
        logger.info(f"✅ 候选人 {candidate_id} 笔记保存成功，内容长度: {len(notes)}")
        
        return JSONResponse(content={
            "success": True,
            "message": "笔记保存成功",
            "candidate_id": candidate_id,
            "notes": notes,
            "updated_at": app_state["candidate_notes"][candidate_id]["updated_at"]
        })
        
    except Exception as e:
        logger.error(f"❌ 保存笔记失败: {e}")
        return JSONResponse(status_code=500, content={
            "success": False,
            "error": f"保存笔记失败: {str(e)}"
        })

@app.get("/api/candidates/{candidate_id}/notes")
async def get_candidate_notes(candidate_id: str):
    """获取候选人笔记"""
    try:
        logger.info(f"📖 获取候选人 {candidate_id} 的笔记")
        
        # 优先从简历对象获取最新笔记（多智能体更新的位置）
        resume_notes = ""
        resume_found = False
        for resume in data_manager.resumes:
            if resume.id == candidate_id:
                resume_notes = getattr(resume, 'notes', '')
                resume_found = True
                break
        
        # 从全局状态获取笔记作为备选
        notes_data = app_state["candidate_notes"].get(candidate_id)
        
        # 优先使用简历对象的笔记（这是多智能体更新的地方）
        if resume_found and resume_notes:
            notes = resume_notes
            # 同步更新到全局状态，确保一致性
            app_state["candidate_notes"][candidate_id] = {
                "notes": resume_notes,
                "updated_at": datetime.now().isoformat(),
                "updated_by": "System_Sync"
            }
            updated_at = app_state["candidate_notes"][candidate_id]["updated_at"]
        elif notes_data:
            notes = notes_data["notes"]
            updated_at = notes_data["updated_at"]
        else:
            notes = ""
            updated_at = datetime.now().isoformat()
        
        logger.info(f"✅ 候选人 {candidate_id} 笔记获取成功，内容长度: {len(notes)}")
        
        return JSONResponse(content={
            "success": True,
            "candidate_id": candidate_id,
            "notes": notes,
            "updated_at": updated_at
        })
        
    except Exception as e:
        logger.error(f"❌ 获取笔记失败: {e}")
        return JSONResponse(status_code=500, content={
            "success": False,
            "error": f"获取笔记失败: {str(e)}"
        })

@app.get("/api/jobs")
async def get_jobs():
    """获取岗位列表"""
    try:
        if not app_state["initialized"]:
            raise HTTPException(status_code=503, detail="系统尚未初始化完成")
        
        jobs_list = []
        for i, job in enumerate(data_manager.jobs):
            jobs_list.append({
                "id": job.id,
                "title": job.title,
                "full_title": job.short_title,  # 前端期望的字段名
                "company": job.company_name,
                "location": job.location,
                "salary": job.salary_year_avg,
                "required_skills": job.required_skills,
                "preferred_skills": job.preferred_skills,
                "min_experience": job.min_experience_years,
                "description": job.description[:200] + "..." if len(job.description) > 200 else job.description,
                "urgent": i == 0,  # 第一个岗位设为紧急
                "applicants": 12 + (i * 7)  # 模拟申请人数
            })
        
        return JSONResponse(content={
            "success": True,
            "data": jobs_list,
            "total": len(data_manager.jobs)
        })
        
    except Exception as e:
        logger.error(f"获取岗位失败: {e}")
        return JSONResponse(content={
            "success": False,
            "error": str(e)
        }, status_code=500)

@app.get("/api/jobs/{job_id}/candidates")
async def get_job_candidates(job_id: str):
    """获取指定岗位的候选人列表"""
    try:
        if not app_state["initialized"]:
            raise HTTPException(status_code=503, detail="系统尚未初始化完成")
        
        # 验证岗位存在
        job = data_manager.get_job_by_id(job_id)
        if not job:
            raise HTTPException(status_code=404, detail=f"岗位 {job_id} 不存在")
        
        # 获取候选人列表 (简化：返回所有候选人)
        candidates = data_manager.resumes[:20]  # 限制数量
        
        candidate_list = []
        for i, resume in enumerate(candidates):
            candidate_status = app_state["candidate_status"].get(resume.id, CandidateStatus.UNKNOWN)
            candidate_list.append({
                "id": resume.id,
                "name": f"候选人_{resume.id}",
                "category": resume.category or "未分类",
                "skills": resume.skills or ["暂无技能信息"],
                "experience_years": resume.experience_years or 0,
                "status": candidate_status,
                "status_color": hr_system.get_status_color(candidate_status),
                "tags": [],
                "notes": "",  # 添加notes字段
                "notes_count": 0,
                "score": 7.0 + (i % 3),  # 基于真实数据的匹配度
                "match_percentage": 75 + (i % 25),  # 模拟匹配度 75-99%
                "resume_full_text": resume.content,  # 添加完整简历内容
                "resume_preview": resume.content[:300] + "..." if len(resume.content) > 300 else resume.content,
                "education": "本科",
                "location": resume.location or "北京",
                "salary_expectation": f"{15 + i * 2}-{20 + i * 3}k",
                "contact_info": {
                    "email": f"candidate_{resume.id[:8]}@example.com",
                    "phone": f"138****{1000 + i:04d}"
                }
            })
        
        return JSONResponse(content={
            "success": True,
            "data": candidate_list,
            "job": {
                "id": job.id,
                "title": job.title,
                "company": job.company_name
            },
            "total": len(candidate_list)
        })
        
    except HTTPException as e:
        raise e
    except Exception as e:
        logger.error(f"获取岗位候选人失败: {e}")
        return JSONResponse(content={
            "success": False,
            "error": str(e)
        }, status_code=500)

def start_server(host: str = "0.0.0.0", port: int = 8089):
    """启动BoLe智能HR多智能体系统服务器"""
    print(f"""
╔══════════════════════════════════════════════════════════════════╗
║               🤖 BoLe 智能HR系统 - 多智能体版 🤖              ║
║              LangGraph多智能体 • 真实AI驱动招聘              ║
╚══════════════════════════════════════════════════════════════════╝

🌐 服务器地址: http://{host}:{port}
🎯 Living Workspace: http://{host}:{port}/living_workspace.html
🖥️ 管理后台: http://{host}:{port}/static/candidate_status.html

🧠 **多智能体架构:**
   • Interaction → Orchestrator → CandidateAnalysis → DeepAnalysis → Tools → Completion
   • 真实AI驱动，无预设回复，每个响应都是智能生成

🔧 **智能功能:**
   • 🎯 语义理解：'找几个身心健康、积极主动的Python工程师'
   • 📊 深度分析：生成能力雷达图、技能对比图、综合报告
   • 🤖 智能面试：基于候选人背景生成个性化面试题
   • 🔍 多维筛选：技能、经验、教育背景、软技能综合评估

💬 **AI对话示例:**
   • "找几个身心健康的Python开发者"
   • "为候选人12345678生成深度分析报告"
   • "筛选有创新精神的机器学习专家"
   • "分析候选人87654321与岗位的匹配度"

🛠️ **技术栈:**
   LangGraph + LangChain + OpenAI/通义千问 + FastAPI + 异步处理

⚡ 启动多智能体系统中...
""")
    
    try:
        uvicorn.run(
            app,
            host=host,
            port=port,
            log_level="info"
        )
    except KeyboardInterrupt:
        logger.info("\n👋 用户中断，系统关闭")
    except Exception as e:
        logger.error(f"💥 服务器启动失败: {e}")
        raise

if __name__ == "__main__":
    start_server(port=8089)
